﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using DDD.Core;

namespace DDD.OpenTK {
    /// <summary>
    /// <see cref="Mesh"/>クラスに拡張メソッドを追加するクラス
    /// </summary>
    public static class MeshExtensions {


        /// <summary>
        /// コンパイル
        /// </summary>
        /// <remarks>
        /// 有効でないサブメッシュをコンパイルすると例外が発生する場合があります。
        /// </remarks>
        /// <param name="msh"><see cref="Mesh"/>オブジェクト</param>
        public static void Compile (this Mesh msh) {
            if (msh.VertexBuffer == null || msh.IndexBuffer == null || msh.Appearance == null) {
                throw new ArgumentNullException ("Submesh[0] is invalid(null)");
            }
            var cache = Graphics3DExtensions.GetGLCache ();

            foreach (var submesh in msh.Submeshes) {
                var vbuf = submesh.VertexBuffer;
                var ibuf = submesh.IndexBuffer;
                var app = submesh.Appearance;

                app.Compile ();   // must be 1st
                vbuf.Compile (app.ShaderProgram);
                ibuf.Compile ();
            }
        }

        /// <summary>
        /// レンダリング
        /// </summary>
        /// <remarks>
        /// 有効でないサブメッシュをレンダリングすると例外が発生する場合があります。
        /// </remarks>
        /// <param name="msh"><see cref="Mesh"/>オブジェクト</param>
        /// <param name="node">カレントのノード</param>
        public static void Render (this Mesh msh, Node node) {
            if (msh.VertexBuffer == null || msh.IndexBuffer == null || msh.Appearance == null) {
                throw new ArgumentNullException ("Submesh[0] is invalid(null)");
            }
            var cache = Graphics3DExtensions.GetGLCache ();
            ErrorCode err;

            int q;
            GL.GenQueries (1, out q);
            GL.BeginQuery (QueryTarget.SamplesPassed, q);

            foreach(var m in msh.Submeshes) {
                var vbuf = m.VertexBuffer;
                var ibuf = m.IndexBuffer;
                var app = m.Appearance;

                app.Render (node);   // must be 1st
                vbuf.Render ();
                ibuf.Render ();

                var primType = ibuf.PrimitiveType.ToGL ();
                var indexCount = ibuf.IndexCount;
                var indexType = ibuf.IndexType.ToGL ();

                GL.DrawElements (primType, indexCount, indexType, 0);
                if ((err = GL.GetError ()) > 0) {
                    throw new InvalidOperationException ("glDrawElements was failed, err=" + err);
                }
            }

            GL.EndQuery (QueryTarget.SamplesPassed);

            int num;
            GL.GetQueryObject (q, GetQueryObjectParam.QueryResult, out num);
            Console.WriteLine ("num = " + num);

            GL.DeleteQueries (1, ref q);

            // デフォルトに戻す
            // (注意)全部のステートを戻しているわけではない
            GL.UseProgram (0);
            GL.BindVertexArray (0);
            GL.BindBuffer (BufferTarget.ElementArrayBuffer, 0);
            GL.ActiveTexture (TextureUnit.Texture0);
        }


    }
}
